module ALU(
    input [63:0] data1,
    input [63:0] data2,
    input [16:0] ALUControl,

    output reg [63:0] res
);

    wire [63:0] sum = data1 + data2;
    wire [63:0] sub = data1 - data2;
    wire [63:0] sll = data1 << data2[5:0];
    wire [31:0] sllw = data1 << data2[4:0];
    wire [63:0] srl = data1 >> data2[5:0];
    wire [31:0] srlw = data1[31:0] >> data2[4:0];
    wire [63:0] sra = $signed(data1) >>> data2[5:0];
    wire [31:0] sraw = $signed(data1[31:0]) >>> data2[4:0];
    wire is_less = data1[63] == 0 ? (data2[63] == 1 ? 0 : data1 < data2) : (data2[63] == 0 ? 1 : data1 < data2);

    always @(*) begin
        case(ALUControl)
            17'b10000000000000000: begin //add
                res = sum;
            end
            17'b01000000000000000 : begin //addw
                res = {{32{sum[31]}}, sum[31:0]};
            end
            17'b00100000000000000: begin //sub
                res = sub;
            end
            17'b00010000000000000: begin //subw
                res = {{32{sub[31]}}, sub[31:0]};
            end
            17'b00001000000000000: begin //lui
                res = {data2[51:0], 12'd0};
            end
            17'b00000100000000000: begin //auipc
                res = sum;
            end
            17'b00000010000000000: begin //xor
                res = data1 ^ data2;
            end
            17'b00000001000000000: begin //or
                res = data1 | data2;
            end
            17'b00000000100000000: begin //and
                res = data1 & data2;
            end
            17'b00000000010000000: begin //slt
                res = (data1 < data2) ? 64'd1 : 64'd0;
            end
            17'b00000000001000000: begin //sll
                res = sll;
            end
            17'b00000000000100000: begin //sllw
                res = {{32{sllw[31]}}, sllw[31:0]};
            end
            17'b00000000000010000: begin //srl
                res = srl;
            end
            17'b00000000000001000: begin //srlw
                res = {{32{srlw[31]}}, srlw[31:0]};
            end
            17'b00000000000000100: begin //sra
                res = sra;
            end
            17'b00000000000000010: begin //sra
                res = {{32{sraw[31]}}, sraw[31:0]};
            end
            17'b00000000000000001: begin //sra
                res = is_less ? 64'd1 : 64'd0;
            end
            default : begin
                res = 64'd0;
            end
        endcase
    end

endmodule
